﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using FinPlusInterfaces;
using FinPlusAssembler;
using FinPlusCompCore;

namespace FinPlusCompTDD
{
    //TODO under construction
    public class FinPlusDPodStub : FinPlusComponent, IFinPlusConnect
    {
        [State(Test = true)]
        public override bool IsValid { get; set; }
        [State(Test = true)]
        public override string TestString { get { return Adapter.ToString(); } }
        public override IPods Adapter { get { return _adapter.ToPods(); } }
        public bool CanWrite { get { return true; } }

        private delegate void transPool(IPods transactions);
        private IDPods _adapter;
        private readonly IDictionary<string, IPods> _trans = new Dictionary<string, IPods>();
        private readonly string _path;
        private DateTime _firstTrans = DateTime.MinValue, _started = DateTime.Now;
        private TimeSpan _syncOffset;

        //construct
        public FinPlusDPodStub(string name, TimeSpan syncOffset)
        {
            _path = string.Format("{0}{1}.{2}", Paths.Values["FolderLogs"], name, FileType.stub);
            _syncOffset = syncOffset;

            DataInvoke();
            TransPool();
            TransInvoke();
        }

        //common control interface
        public override void Dispose(){ }

        //public
        public IDPods DPods() { return _adapter; }

        public IPods Pods() { return _adapter.ToPods(); }

        //private
        private void DataInvoke()
        {
            var pods = IOC.New<IPods>(_path, "root/data");
            _adapter = IOC.New<IDPods>(pods);
        }

        private void TransPool()
        {
            try
            {
                var trans = IOC.New<IPods>(_path, "root/transactions");
                foreach (var transaction in trans.Values)
                {
                    var threadId = transaction.Get(BeanField.ThreadId.ToString());
                    if(_firstTrans < threadId.TimeStamp ) _firstTrans = threadId.TimeStamp;
                   
                    if (!_trans.ContainsKey(threadId.Value))
                        _trans[threadId.Value] = IOC.New<IPods>();

                    _trans[threadId.Value].Add(transaction);
                }

                _syncOffset = _started.Subtract(_firstTrans).Add(_syncOffset);
            }
            catch (TDDConfigException e)
            {
                IsValid = Level.Error.Log(Id, Config, _path, e);
            }
        }

        private void TransInvoke()
        {
            try
            {
                var syncTime = DateTime.Now.Add(_syncOffset);
                foreach(var tran in _trans.Values)
                {
                    var thread = new transPool(TransRun);
                    thread.Invoke(tran);
                }
            }
            catch (TDDConfigException e)
            {
                IsValid = Level.Error.Log(Id, Config, _path, e);
            }
        }

        private void TransRun(IPods trans)
        {
            foreach (var tran in trans.Values)
            {
                IDPod dPod;
                var id = tran[BeanField.LinkedId.ToString()].ToString();
                if (_adapter.TryGet(id, out dPod))
                {
                    foreach (var bean in tran)
                    {
                        var sleep = DateTime.Now.Subtract(bean.TimeStamp.Add(_syncOffset));
                        Thread.Sleep(sleep);
                        dPod.SetBean(bean);
                    }
                }
            }
        }
    }
}
